要學習的東西太多了,最後幾天有點亂掉,今天就來研究gRPC
吧。
RPC
是Remote Procedure Calls
(遠端程序呼叫)的簡稱。一種遠端遠端調用程式的模組,可以讓遠端程式可以透過網路通訊方法呼叫本地function
與method
的一種方法。簡單一點的解說,今天有A、B兩台伺服器,A伺服器想要呼叫B伺服器提供的函式,但因為不在同一個空間,不能直接呼叫,透過網路通訊方法模擬直接從本地呼叫的樣式,即為RPC
。
概念大概如下:
Client
從遠端呼叫一個function
function
的參數會被打包成特定格式的封包Server
接收封包function
的參數格式function
後朝client
回傳result
gRPC
(Remote Procedure Calls)是Google發起的一個開源的RPC
系統。可以更輕鬆地創建分佈式應用程序和服務。
Protobuf
格式傳輸資料HTTP/2
通訊協定,效能好(Unary)
:一個request
,一個response
,與一般http
請求一樣,只是是透過gRPC
協定。(Streaming)
:client
發送一個request
後,server
可以多次response
。(Bidirectional streaming)
:同WebSocket
,傳輸格式透過schema
定義,兩邊都可以多次request
與reponse
。由於版本更新之前網路上相關文章有些使用方法已經不能使用了,目前統整的是我自己能使用的方式。
protobuf
go get -u google.golang.org/protobuf
gRPC
go get -u google.golang.org/grpc
protobuf-compiler
Protocol Compiler
。在終端機輸入下面兩行,go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
這樣基本套件應該都載入好了。
在開發之前要先撰寫Protobuf
檔,定義資料交換的相關資料,因此建立一個以proto
為副檔名的檔案。
syntax = "proto3";
option go_package = "./protobuffer";
//定義Service名稱,
service SaySomethingService{
//定義api名稱,傳入參數與回傳值
rpc TestRPC (testRequest) returns (testResponse) {}
}
//傳入參數的spec
message testRequest {
int64 id = 1;
}
//回傳值的spec
message testResponse {
string name = 1;
float heigh = 2;
float weight = 3;
}
在參數後的 = <數字> ;
是指輸入與輸出順序。相關方法定義好後,在終端機輸入以下指令
protoc --go_out=. --go-grpc_out=. test.proto
執行後會依照上方option go_package
放入兩個.pb.go
的檔案,這就是protoc
編譯器幫忙使用定義好的proto
檔產生的go
檔案。
正常來說兩份檔案應該要指向同一支protobuffer
,我這邊偷懶了一下兩邊都編譯出了.pb.go
檔
package main
import (
"context"
"log"
"net"
pb "grpc-test/protobuffer"
"google.golang.org/grpc"
)
const (
port = ":8080"
)
type server struct{}
func main() {
// Create gRPC Server
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
log.Println("gRPC server is running.")
pb.RegisterSaySomethingServiceServer(s, &server{})
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
//
func (s *server) TestRPC(ctx context.Context, in *pb.TestRequest) (*pb.TestResponse, error) {
log.Println("i receive:", in.Id)
return &pb.TestResponse{Name: "Jay", Weight: 75, Heigh: 170}, nil
}
這邊執行下來&server{}
那邊會出錯,貌似是因為interface
沒有將所有功能實作完,我有到test_grpc.pb.go
中將下面功能做註解。
type SaySomethingServiceServer interface {
// 定義api名稱,傳入參數與回傳值
TestRPC(context.Context, *TestRequest) (*TestResponse, error)
// 註解掉下面這行
// MustEmbedUnimplementedSaySomethingServiceServer()
}
順利的話應該能執行起來讓伺服器運行。
用另一支Go程式模擬客戶端,這邊只是隨意發送一筆int
值,讓server
端回傳寫好的內容而已,實際運用時這邊可以做function
的調用。
package main
import (
"context"
pb "grpc-client/protobuffer"
"log"
"time"
"google.golang.org/grpc"
)
const (
address = "localhost:8080"
)
func main() {
conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewSaySomethingServiceClient(conn)
TestRPC(c, 12)
}
//
func TestRPC(c pb.SaySomethingServiceClient, id int64) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
res, err := c.TestRPC(ctx, &pb.TestRequest{Id: id })
if err != nil {
log.Fatalf("could not mkdfk2020: %v", err)
}
log.Printf("gRPC response: %s", res)
}
server output:
2022/10/11 13:09:16 gRPC server is running.
2022/10/11 13:09:25 i receive: 12
client output:
2022/10/11 13:09:25 gRPC response: name:"Jay" heigh:170 weight:75
gRPC
服務。gRPC
是使用Protobuf
進行編碼,雖可高效率傳送,但人工不可讀。Protobuf
規範,雖嚴謹但較費時。gRPC
就介紹到這吧,原本以為都照著別人的腳步走應該可以學很快,結果遇到版本更新問題,滿多地方照做都出錯,額外花了許多時間來整理今天的筆記,希望可以幫到閱讀者以及未來的自己ˊˇˋ
Day29-Go gRPC(下)
https://ithelp.ithome.com.tw/articles/10278704
[DAY20]GO gRPC初體驗
https://ithelp.ithome.com.tw/articles/10243863
Day31 Golang Protobuf 介紹與使用
https://ithelp.ithome.com.tw/articles/10250131
plugins are not supported : grpc #1070
https://github.com/golang/protobuf/issues/1070
DAY9 — 神奇的 gRPC,讓你把 call service 當成一個 function call — 概念篇
https://ithelp.ithome.com.tw/articles/10242372
使用 Golang 建立一個 gRPC 架構
https://keronscribe.tw/golang-grpc-unary
Day 16 - 分散式系統溝通的方法 - RPC
https://ithelp.ithome.com.tw/articles/10223580